package com.anttribe.components.db.metadata.supplier;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.anttribe.components.db.metadata.Dialect;
import com.anttribe.components.db.metadata.datasource.DataSourceProxy;
import com.anttribe.components.db.metadata.exception.DbException;

import lombok.extern.slf4j.Slf4j;

/**
 * @author zhaoyong
 * @date 2021/10/17 0017
 */
@Slf4j
public class DatabaseSupplierFactory {

    /**
     * <私有>
     */
    private DatabaseSupplierFactory() {}

    /**
     * DatabaseSupplierFactory
     *
     * @return DatabaseSupplierFactory
     */
    public static DatabaseSupplierFactory me() {
        return DatabaseSupplierFactoryInstance.INSTANCE;
    }

    /**
     * 获取DatabaseSupplier实例对象
     *
     * @param dataSource
     *            DataSource
     * @return DatabaseSupplier
     */
    public DatabaseSupplier getDatabaseSupplier(DataSource dataSource) {
        if (null == dataSource) {
            throw new DbException("dataSource must not be null");
        }

        // 根据数据库类型获取对应DatabaseSupplier
        DataSourceProxy dataSourceProxy = new DataSourceProxy(dataSource);
        try {
            Dialect dialect = dataSourceProxy.getDialect();
            if (null == dialect || null == dialect.getSupplierClass()) {
                throw new DbException("can not resolve db dialect");
            }

            Class<? extends DatabaseSupplier> supplierClass = dialect.getSupplierClass();
            Constructor<? extends DatabaseSupplier> constructor = supplierClass.getConstructor(DataSource.class);
            return constructor.newInstance(dataSourceProxy);
        } catch (SQLException | NoSuchMethodException | IllegalAccessException | InstantiationException
            | InvocationTargetException e) {
            throw new DbException(e);
        }
    }

    /**
     * 静态内部类实现单例
     *
     * @author zhaoyong
     * @date 2020-12-21
     */
    private static class DatabaseSupplierFactoryInstance {

        public static final DatabaseSupplierFactory INSTANCE = new DatabaseSupplierFactory();

    }

}
